1 module hip.api.data.audio; 2 3 import hip.api.audio; 4 public import hip.api.audio.audioclip; 5 6 enum HipAudioEncoding : ubyte 7 { 8 WAV, 9 MP3, 10 OGG, 11 MIDI, //Probably won't support 12 FLAC, 13 MOD, 14 XM 15 } 16 17 HipAudioEncoding getEncodingFromName(string name) 18 { 19 int i = cast(int)name.length-1; 20 while(i >= 0 && name[i] != '.'){i--;} if(name[i] == '.') i++; 21 switch(name[i..$]) 22 { 23 case "wav":return HipAudioEncoding.WAV; 24 case "ogg":return HipAudioEncoding.OGG; 25 case "mp3":return HipAudioEncoding.MP3; 26 case "flac":return HipAudioEncoding.FLAC; 27 case "mod": return HipAudioEncoding.MOD; 28 case "xm": return HipAudioEncoding.XM; 29 case "mid": 30 case "midi":return HipAudioEncoding.MIDI; 31 default: assert(false, "Encoding from file '"~name~", is not supported."); 32 } 33 } 34 35 interface IHipAudioDecoder 36 { 37 bool decode(in ubyte[] data, HipAudioEncoding encoding, HipAudioType type, 38 void delegate(in ubyte[] data) onSuccess, void delegate() onFailure); 39 40 bool resample(in ubyte[] data, HipAudioType type, uint outputSampleRate, uint outputChannels, 41 void delegate(in ubyte[] data) onSuccess, void delegate() onFailure); 42 43 ///Channel conversion is a very simple implementation, so, I won't use delegates for it. 44 bool channelConversion(in ubyte[] data, ubyte from, ubyte to); 45 /** 46 * Receives the raw data. Deals with the data based on clip hint. 47 */ 48 final bool loadData(in ubyte[] data, HipAudioEncoding encoding, HipAudioType type, HipAudioClipHint hint, 49 void delegate(in ubyte[] data) onSuccess, void delegate() onFailure) 50 { 51 if(data.length == 0) 52 { 53 onFailure(); 54 return false; 55 } 56 57 if(hint.needsDecode) 58 { 59 decode(data, encoding, type, (in ubyte[] decodedData) 60 { 61 if(hint.needsResample && getSamplerate != hint.outputSamplerate) 62 { 63 resample(decodedData, type, hint.outputSamplerate, hint.outputChannels, (in ubyte[] resampledData) 64 { 65 if(hint.needsChannelConversion && getClipChannels != hint.outputChannels && 66 !channelConversion(resampledData, getClipChannels, cast(ubyte)hint.outputChannels)) 67 { 68 onFailure(); 69 return; 70 } 71 onSuccess(getClipData); 72 }, onFailure); 73 } 74 else 75 onSuccess(decodedData); 76 }, onFailure); 77 } 78 else if(hint.needsResample && getSamplerate != hint.outputSamplerate) 79 { 80 resample(getClipData, type, hint.outputSamplerate, hint.outputChannels, (in ubyte[] resampledData) 81 { 82 if(hint.needsChannelConversion && getClipChannels != hint.outputChannels && 83 !channelConversion(resampledData, getClipChannels, cast(ubyte)hint.outputChannels)) 84 onFailure(); 85 onSuccess(getClipData); 86 }, onFailure); 87 } 88 else if(hint.needsChannelConversion && getClipChannels != hint.outputChannels) 89 { 90 channelConversion(getClipData, getClipChannels, cast(ubyte)hint.outputChannels); 91 onSuccess(getClipData); 92 } 93 94 return true; 95 } 96 ///Used for streaming. 97 uint startDecoding(in ubyte[] data, ubyte[] outputDecodedData, uint chunkSize, HipAudioEncoding encoding) 98 in (chunkSize > 0 , "Chunk size must be greater than 0"); 99 uint updateDecoding(ubyte[] outputDecodedData); 100 AudioConfig getAudioConfig(); 101 ubyte[] getClipData(); 102 ubyte getClipChannels(); 103 size_t getClipSize(); 104 ///Don't apply to streamed audio. Gets the duration in seconds 105 float getDuration(); 106 107 void dispose(); 108 uint getSamplerate(); 109 110 } 111 112 enum AudioFormat : ushort 113 { 114 signed8, 115 signed16Little, 116 signed16Big, 117 signed32Little, 118 signed32Big, 119 unsigned8, 120 unsigned16Little, 121 unsigned16Big, 122 float32Little, 123 float32Big, 124 _default = signed16Little 125 } 126 127 enum audioConfigDefaultBufferSize = 4096; 128 129 130 pragma(LDC_no_typeinfo) 131 struct AudioConfig 132 { 133 int sampleRate; 134 AudioFormat format; 135 uint channels; 136 int bufferSize; 137 138 static enum defaultBufferSize = audioConfigDefaultBufferSize; 139 140 141 142 /** 143 * Returns a default audio configuration for 2D 144 */ 145 static AudioConfig musicConfig() 146 { 147 return AudioConfig(44_100, AudioFormat.float32Little, 2, audioConfigDefaultBufferSize); 148 } 149 static AudioConfig androidConfig() 150 { 151 return AudioConfig(22_050, AudioFormat.float32Little, 1U, 2048); 152 } 153 static AudioConfig lightweightConfig() 154 { 155 return AudioConfig(22_050, AudioFormat._default, 1U, 2048); 156 } 157 158 uint getBitDepth() 159 { 160 switch(format) with(AudioFormat) 161 { 162 case signed8: 163 case unsigned8: 164 return 8; 165 case signed16Big: 166 case signed16Little: 167 case unsigned16Big: 168 case unsigned16Little: 169 return 16; 170 case signed32Big: 171 case signed32Little: 172 case float32Big: 173 case float32Little: 174 return 32; 175 default:return 0; 176 } 177 } 178 }